package com.sicau.socialpracticesystem.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sicau.socialpracticesystem.common.constant.UrlConstants;
import com.sicau.socialpracticesystem.common.myenum.OriginAddressEnum;
import com.sicau.socialpracticesystem.common.myenum.TeamMemberStateEnum;
import com.sicau.socialpracticesystem.common.myenum.TeamMemberRoleEnum;
import com.sicau.socialpracticesystem.common.myenum.TeamProgressEnum;
import com.sicau.socialpracticesystem.common.returning.ResultData;
import com.sicau.socialpracticesystem.config.aop.ValidateAspect;
import com.sicau.socialpracticesystem.config.dozer.DozerUtils;
import com.sicau.socialpracticesystem.entity.param.PageParam;
import com.sicau.socialpracticesystem.entity.param.team.TeamAddParam;
import com.sicau.socialpracticesystem.entity.param.team.TeamQueryParam;
import com.sicau.socialpracticesystem.entity.param.team.TeamRouteQueryParam;
import com.sicau.socialpracticesystem.entity.param.team.TeamUpdateParam;
import com.sicau.socialpracticesystem.entity.po.Team;
import com.sicau.socialpracticesystem.entity.po.TeamMember;
import com.sicau.socialpracticesystem.entity.vo.PageDataVO;
import com.sicau.socialpracticesystem.entity.vo.team.TeamRouteVO;
import com.sicau.socialpracticesystem.entity.vo.team.TeamVO;
import com.sicau.socialpracticesystem.repository.TeamRepository;
import com.sicau.socialpracticesystem.service.TeamMemberService;
import com.sicau.socialpracticesystem.service.TeamService;
import com.sicau.socialpracticesystem.util.InverseGeoUtil;
import com.sicau.socialpracticesystem.util.UserContext;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;

/**
 * <p>
 * 支队表 前端控制器
 * </p>
 *
 * @author sxt && ttxxi
 * @since 2021-04-26
 */
@RestController
@PreAuthorize("isAuthenticated()")
@Api(tags = "团队相关接口")
@RequestMapping(UrlConstants.TEAM_PREFIX)
public class TeamController {

    @Resource
    private DozerUtils dozerUtils;

    @Resource
    private TeamService teamService;

    @Resource
    private TeamRepository teamRepository;

    @Resource
    private TeamMemberService teamMemberService;

    @GetMapping("/team-route")
    @PreAuthorize("permitAll()")
    @ApiOperation("查询团队路线列表（地图用）")
    @ValidateAspect.ParamValidate
    public ResultData<List<TeamRouteVO>> getAllTeamRoute(@Valid TeamRouteQueryParam teamRouteQueryParam,
                                                         @ApiParam(hidden = true)
                                                         @SuppressWarnings("unused") BindingResult bindingResult) {
        return new ResultData<List<TeamRouteVO>>().OK().setObj(teamService.queryAllTeamRoute(teamRouteQueryParam));

    }

    @GetMapping("/{id}")
    @ApiOperation("根据id查询团队信息")
    public ResultData<TeamVO> getTeamById(@PathVariable Integer id) {
        TeamVO teamVO = teamService.queryTeamById(id);
        teamVO.setTeamMemberVOList(teamMemberService.queryTeamMemberByTeamId(id));
        return new ResultData<TeamVO>().OK().setObj(teamVO);
    }


    @PostMapping
    @ApiOperation("添加一个团队")
    @ValidateAspect.ParamValidate
    public ResultData<Object> addTeam(@RequestBody @Valid TeamAddParam teamAddParam,
                                      @ApiParam(hidden = true)
                                      @SuppressWarnings("unused") BindingResult bindingResult) {


        Team team = dozerUtils.map(teamAddParam, Team.class);
        team.setCreatorId(UserContext.get().getId());
        team.setHasMemberCount(1);
        team.setExcellentTeam(0);
        team.setProgress(TeamProgressEnum.CREATE.getId());
        OriginAddressEnum originAddressEnum = OriginAddressEnum.getEnum(team.getOriginAddress());
        InverseGeoUtil.LatLng originLatLng = InverseGeoUtil.inverse(originAddressEnum != null
                ? originAddressEnum.getAddress()
                : OriginAddressEnum.ORIGIN_CHENG_DU.getAddress());
        InverseGeoUtil.LatLng destinationLatLng = InverseGeoUtil.inverse(team.getDestinationAddress());
        team.setOriginLat(originLatLng.getLatitude())
                .setOriginLng(originLatLng.getLongitude())
                .setDestinationLat(destinationLatLng.getLatitude())
                .setDestinationLng(destinationLatLng.getLongitude());

        //jpa保存team
        Team savedTeam = teamRepository.save(team);
        //保存团队成员信息，设置队长
        teamMemberService.save(
                new TeamMember(savedTeam.getId(),
                        savedTeam.getCreatorId(),
                        TeamMemberStateEnum.PASSED.getState(),
                        TeamMemberRoleEnum.CAPTAIN.getRole()));

        return new ResultData<>().OK();
    }

    @GetMapping
    @PreAuthorize("permitAll()")
    @ApiOperation("查询团队(带分页)")
    public ResultData<PageDataVO<TeamVO>> getTeams(TeamQueryParam teamQueryParam) {
        PageDataVO<TeamVO> teamVOPageDataVO = teamService.queryTeamByConditions(teamQueryParam);
        return new ResultData<PageDataVO<TeamVO>>().OK().setObj(teamVOPageDataVO);
    }

    @GetMapping("selfTeams")
    @ApiOperation("查询自己所在的团队(带分页)")
    public ResultData<PageDataVO<TeamVO>> getTeamsOfSelf(PageParam pageParam) {
        return new ResultData<PageDataVO<TeamVO>>()
                .OK()
                .setObj(teamService.queryCurrentTeams(pageParam));
    }

    @PutMapping("/{id}")
    @ApiOperation("修改团队信息")
    @ValidateAspect.ParamValidate()
    public ResultData<Object> updateTeam(@PathVariable("id") Integer id,
                                         @RequestBody @Valid TeamUpdateParam teamUpdateParam,
                                         @ApiParam(hidden = true)
                                         @SuppressWarnings("unused") BindingResult bindingResult) {
        Team team = teamService.getById(id);
        if (team.getAllMemberCount() < team.getHasMemberCount()) {
            return new ResultData<>().FAILED().setResultIns("修改的团队数量不能小于团队已有人数");
        }
        dozerUtils.map(teamUpdateParam, team);
        return teamService.updateById(team)
                ? new ResultData<>().OK().setObj(teamService.queryTeamById(id))
                : new ResultData<>().FAILED();
    }

    @GetMapping("apply/{id}")
    @ApiOperation("用户申请加入团队")
    public ResultData<Object> applyJoinTeam(@PathVariable Integer id) {
        Team team = teamService.getOne(new LambdaQueryWrapper<Team>().eq(Team::getId, id));
        if (team == null) {
            return new ResultData<>().setResultIns("团队不存在");
        }
        Integer currentUserId = UserContext.get().getId();
        if (team.getCreatorId().equals(currentUserId)) {
            return new ResultData<>().setResultIns("你就是队长不需要申请");
        }
        if (!isUserHasAppliedTheTeam()) {
            return teamMemberService.save(new TeamMember(id, currentUserId, TeamMemberStateEnum.HAS_APPLIED.getState(), TeamMemberRoleEnum.MEMBER.getRole()))
                    ? new ResultData<>().OK()
                    : new ResultData<>().FAILED();
        }
        return new ResultData<>().FAILED().setResultIns("已经申请过本实践团队了");
    }

    @GetMapping("judgeUserHasAppliedTheTeam")
    @ApiOperation("检测当前登录用户是否已申请某实践团队(返回说明: 0: 未申请, 1: 已申请, 2: 登录用户就是队长自己, 3: 团队不存在, 4: 团队成员已满)")
    @ApiImplicitParam(name = "teamId", value = "团队id", required = true)
    public ResultData<Integer> judgeUserHasAppliedTheTeam(@RequestParam() Integer teamId) {
        Team team = teamService.getOne(new LambdaQueryWrapper<Team>().eq(Team::getId, teamId));
        if (team == null) {
            return new ResultData<Integer>().setResultIns("团队不存在").setObj(3);
        }
        Integer currentUserId = UserContext.get().getId();
        if (team.getCreatorId().equals(currentUserId)) {
            return new ResultData<Integer>().setResultIns("登录用户就是队长自己").setObj(2);
        }
        if (isUserHasAppliedTheTeam()) {
            return new ResultData<Integer>().setResultIns("已申请").setObj(1);
        }
        if (team.getAllMemberCount() <= team.getHasMemberCount()) {
            return new ResultData<Integer>().setResultIns("团队成员已满").setObj(4);
        }
        return new ResultData<Integer>().setResultIns("未申请").setObj(0);
    }

    @PutMapping("/initiateTeamOrReverse/{id}")
    @ApiOperation("管理员通过新建团队使团队立项或反悔使得已经'立项'的团队重新变为'新建'的状态, " +
            "注意: 若团队已经处在'新闻稿'及后续的状态, 则本接口调用无效, 因为团队已经在实践当中," +
            "意思是本接口只允许团队状态在 '新建' 和 '立项' 状态之间进行切换'")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @ApiImplicitParam(name = "id", value = "团队id")
    public ResultData<Object> initiateTeamOrReverse(@PathVariable("id") Integer id) {
        Team team = teamService.getById(id);
        TeamProgressEnum teamProgress = TeamProgressEnum.getEnum(team.getProgress());
        if (teamProgress != null) {
            if (teamProgress.equals(TeamProgressEnum.CREATE)) {
                team.setProgress(TeamProgressEnum.INITIATE.getId());
                teamService.updateById(team);
                return new ResultData<>().OK().setResultIns("团队状态修改为'立项'");
            } else if (teamProgress.equals(TeamProgressEnum.INITIATE)) {
                team.setProgress(TeamProgressEnum.CREATE.getId());
                teamService.updateById(team);
                return new ResultData<>().OK().setResultIns("团队状态修改为'创建'");
            } else {
                return new ResultData<>().FAILED().setResultIns("团队状态切换失败, 可能是团队已经处于'新闻稿'及后续的状态");
            }
        } else {
            return new ResultData<>().FAILED().setResultIns("操作异常");
        }
    }

    private boolean isUserHasAppliedTheTeam() {
        TeamMember teamMember = teamMemberService.getOne(new LambdaQueryWrapper<TeamMember>()
                .eq(TeamMember::getUserId, UserContext.get().getId()));

        return teamMember != null;
    }
}

